package com.qijian.maindata.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qijian.common.core.domain.AjaxResult;
import com.qijian.common.core.domain.entity.SysDictData;
import com.qijian.common.exception.ServiceException;
import com.qijian.common.utils.file.AliyunOSSUtil;
import com.qijian.common.utils.file.MimeTypeUtils;
import com.qijian.common.utils.file.ZipUtils;
import com.qijian.common.utils.mybatis.WhereEntityTool;
import com.qijian.common.utils.uuid.IdUtils;
import com.qijian.maindata.domain.InspectionItem;
import com.qijian.maindata.domain.InspectionScheme;
import com.qijian.maindata.domain.InspectionSchemeDetails;
import com.qijian.maindata.domain.excel.InspectionExcelVo;
import com.qijian.maindata.domain.query.InspectionSchemeQuery;
import com.qijian.maindata.domain.vo.InspectionBomVo;
import com.qijian.maindata.domain.vo.InspectionItemVo;
import com.qijian.maindata.domain.vo.InspectionSchemeVo;
import com.qijian.maindata.domain.vo.UpdateItemStorageRequestVo;
import com.qijian.maindata.mapper.InspectionItemDetailMapper;
import com.qijian.maindata.mapper.InspectionItemMapper;
import com.qijian.maindata.mapper.InspectionSchemeMapper;
import com.qijian.maindata.service.IInspectionItemService;
import com.qijian.maindata.service.IInspectionSchemeDetailsService;
import com.qijian.maindata.service.IInspectionSchemeService;
import com.qijian.system.domain.SysConfig;
import com.qijian.system.service.ISysConfigService;
import com.qijian.system.service.ISysDictDataService;
import com.qijian.tool.domain.Storage;
import com.qijian.tool.domain.query.StorageQuery;
import com.qijian.tool.service.IStorageService;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 检验方案-新Service业务层处理
 *
 * @author qijian
 * @date 2024-02-02
 */
@Service
@RequiredArgsConstructor
public class InspectionSchemeServiceImpl extends ServiceImpl<InspectionSchemeMapper, InspectionScheme> implements IInspectionSchemeService {

    private final InspectionSchemeMapper inspectionSchemeMapper;

    private final IInspectionSchemeDetailsService inspectionSchemeDetailsService;

    private final IStorageService storageService;

//    private final IInspectionReportPlanService inspectionReportPlanService;

    private final ISysDictDataService sysDictDataService;


    private final InspectionItemMapper inspectionItemMapper;

    private final InspectionItemDetailMapper inspectionItemDetailMapper;

    private final IInspectionItemService inspectionItemService;

    private final ISysConfigService sysConfigService;

    //初始化的6个默认检验方案
    List<String> codes = Arrays.asList("JYFA-002884","JYFA-002885","JYFA-002886",
            "JYFA-002887","JYFA-002888","JYFA-002889","JYFA-009321","JYFA-008333","JYFA-008334","JYFA-017534");

    @Override
    public boolean saveVo(InspectionSchemeVo inspectionSchemeVo) {
        if(CollUtil.isEmpty(inspectionSchemeVo.getItemIds())){
            throw new ServiceException("检验项为空");
        }
        if(Objects.isNull(inspectionSchemeVo.getId())){
            //新增
            inspectionSchemeVo.setSchemeCode("JYFA-" + String.format("%06d", inspectionSchemeMapper.countWithDel()+1));
            this.save(inspectionSchemeVo);
        }else{
            //修改
            if(inspectionSchemeVo.getIsDefault()){
                throw new ServiceException("E01:默认检验方案不允许修改");
            }
            this.updateById(inspectionSchemeVo);
            inspectionSchemeDetailsService.remove(new LambdaQueryWrapper<InspectionSchemeDetails>().eq(InspectionSchemeDetails::getInspectionId,inspectionSchemeVo.getId()));
        }
        Set<Long> itemIdList = inspectionSchemeVo.getItemIds().stream().map(Long::parseLong).collect(Collectors.toSet());
        List<InspectionSchemeDetails> detailsList = itemIdList.stream().map(itemId -> {
            InspectionSchemeDetails details = new InspectionSchemeDetails();
            details.setInspectionId(inspectionSchemeVo.getId());
            details.setItemId(itemId);
            return details;
        }).collect(Collectors.toList());
        inspectionSchemeDetailsService.saveBatch(detailsList);
        //保存附件
        if(CollUtil.isNotEmpty(inspectionSchemeVo.getFiles())){
            inspectionSchemeVo.getFiles().forEach(action -> {
                action.setClassTable(InspectionScheme.class.getSimpleName());
                action.setClassId(inspectionSchemeVo.getId());
            });
            storageService.updateBatchById(inspectionSchemeVo.getFiles());
        }
        return true;
    }

    @Override
    public InspectionSchemeVo getInfo(Long id) {
        return inspectionSchemeMapper.getInfo(id);
    }

    @Override
    public AjaxResult exportTemplate(HttpServletResponse response) throws Exception {
        return null;
    }

    @Override
    public void doImport(MultipartFile file) throws Exception {

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean importZip(Long schemeId,MultipartFile file) {

        if(Objects.isNull(schemeId)){
            throw new ServiceException("E01:未指定检验方案id无法上传压缩文件");
        }
        //根据检验方案名，找到这个检验方案下面的所有检验项
        List<InspectionItem> inspectionItems =  inspectionItemService.getBySchemeId(schemeId);

        if(CollUtil.isEmpty(inspectionItems)){
            throw new ServiceException("E01:检验方案未创建检验项");
        }
        //所有检验项转成index对应id的数据
        Map<String, Long> itemIndexMap = inspectionItems.stream().filter(s->StrUtil.isNotBlank(s.getItemIndex()))
                .collect(Collectors.toMap(InspectionItem::getItemIndex, InspectionItem::getId));
        //再次校验序号是否为空
        if(CollUtil.isEmpty(itemIndexMap)){
            throw new ServiceException("E01:检验项对应的序号为空,无法上传压缩文件");
        }

        //获得原始文件名;
        String fileRealName = file.getOriginalFilename();
        //点号的位置
        int pointIndex = fileRealName.lastIndexOf(".");
        //截取文件名
        String filePre = fileRealName.substring(0, pointIndex);
        //截取文件后缀
        String fileSuffix = fileRealName.substring(pointIndex);

        String tempPath = System.getProperty("java.io.tmpdir") + File.separator + filePre + "_" + System.currentTimeMillis();
        // 判断文件路径下的文件夹是否存在，不存在则创建
        File zipFile = new File(tempPath);
        if (!zipFile.exists()) {
            zipFile.mkdirs();
        }
        File imageFile = new File(zipFile, "image");
        if (!imageFile.exists()) {
            imageFile.mkdirs();
        }
        try {
            File f = File.createTempFile(fileRealName, fileSuffix);
            if (f.exists()) {
                FileUtils.delete(f);
            }
            file.transferTo(f);
            ZipUtils.getFileType(f, tempPath);
            //遍历path下的文件和目录，放在File数组中
            File[] fs = zipFile.listFiles();
            assert fs != null;
            List<Storage> storages = new ArrayList<>(fs.length);

            //遍历File[]数组
            for (File i : fs) {
                if (!i.isDirectory()) {
                    //判断文件名后缀是不是图片，不是图片不允许上传
                    String suffix = FileUtil.getSuffix(i);
                    if(!isImage(suffix)){
                        throw new ServiceException("E01:上传的压缩包文件必须为图片格式文件(bmp/gif/jpg/jpeg/png)");
                    }
                    //获取到序号
                    String fileName = FileUtil.getPrefix(i);
                    //根据检验方案名+序号名找到方案下的唯一检验项
                    Long itemId = itemIndexMap.get(fileName);
                    if(Objects.nonNull(itemId)){
                        //根据检验项id生成文件
                        //上传阿里云
                        storages.add(createItemZipStorage(i.getName(), filePre, i,itemId));
                    }else{
                        //未匹配到序号报错
                        throw new ServiceException("E01:序号文件["+i.getName()+"]未匹配到检验项");
                    }
                }
            }
            if (CollUtil.isNotEmpty(storages)) {
                storageService.saveOrUpdateBatch(storages);
            }
            FileUtils.delete(f);
            FileUtils.deleteDirectory(zipFile);
        } catch (IOException e) {
            throw new ServiceException("E01:上传压缩包失败"+e.getMessage());
        }
        return true;
    }

    @Override
    public AjaxResult importZipCheck(Long schemeId, MultipartFile file) {

        if(Objects.isNull(schemeId)){
            throw new ServiceException("E01:未指定检验方案id无法上传压缩文件");
        }
        //根据检验方案名，找到这个检验方案下面的所有检验项
//        List<InspectionItem> inspectionItems =  inspectionItemService.getBySchemeId(schemeId);
        InspectionSchemeVo info = inspectionSchemeMapper.getInfo(schemeId);
        if(Objects.isNull(info)){
            throw new ServiceException("E01:检验方案不存在");
        }

        if(CollUtil.isEmpty(info.getDetailsVoList())){
            throw new ServiceException("E01:检验方案未创建检验项");
        }
        //所有检验项转成index对应id的数据
        Map<String, InspectionItemVo> itemIndexMap = info.getDetailsVoList().stream().filter(s->StrUtil.isNotBlank(s.getItemIndex()))
                .collect(Collectors.toMap(InspectionItem::getItemIndex, v->v));
        //再次校验序号是否为空
        if(CollUtil.isEmpty(itemIndexMap)){
            throw new ServiceException("E01:检验项对应的序号为空,无法上传压缩文件");
        }

        //获得原始文件名;
        String fileRealName = file.getOriginalFilename();
        //点号的位置
        int pointIndex = fileRealName.lastIndexOf(".");
        //截取文件名
        String filePre = fileRealName.substring(0, pointIndex);
        //截取文件后缀
        String fileSuffix = fileRealName.substring(pointIndex);

        String tempPath = System.getProperty("java.io.tmpdir") + File.separator + filePre + "_" + System.currentTimeMillis();
        // 判断文件路径下的文件夹是否存在，不存在则创建
        File zipFile = new File(tempPath);
        if (!zipFile.exists()) {
            zipFile.mkdirs();
        }
        File imageFile = new File(zipFile, "image");
        if (!imageFile.exists()) {
            imageFile.mkdirs();
        }
        StringBuffer sb = new StringBuffer();
        try {
            File f = File.createTempFile(fileRealName, fileSuffix);
            if (f.exists()) {
                FileUtils.delete(f);
            }
            file.transferTo(f);
            ZipUtils.getFileType(f, tempPath);
            //遍历path下的文件和目录，放在File数组中
            File[] fs = zipFile.listFiles();
            assert fs != null;
            List<Storage> storages = new ArrayList<>(fs.length);

            //遍历File[]数组
            for (File i : fs) {
                if (!i.isDirectory()) {
                    //判断文件名后缀是不是图片，不是图片不允许上传
                    String suffix = FileUtil.getSuffix(i);
                    if(!isImage(suffix)){
                        throw new ServiceException("E01:上传的压缩包文件必须为图片格式文件(bmp/gif/jpg/jpeg/png)");
                    }
                    //获取到序号
                    String fileName = FileUtil.getPrefix(i);
                    //根据检验方案名+序号名找到方案下的唯一检验项
                    InspectionItemVo inspectionItemVo = itemIndexMap.get(fileName);
                    if(Objects.nonNull(inspectionItemVo)){
                        //根据检验项id 判断文件是否存在
                        if(Objects.nonNull(inspectionItemVo.getStorage())){
                            sb.append("该检验方案已上传序号为[").append(fileName).append("]的图片是否需要覆盖?<br>");
                        }
                    }else{
                        //未匹配到序号报错
                        throw new ServiceException("E01:序号文件["+i.getName()+"]未匹配到检验项");
                    }
                }
            }
            if (CollUtil.isNotEmpty(storages)) {
                storageService.saveOrUpdateBatch(storages);
            }
            FileUtils.delete(f);
            FileUtils.deleteDirectory(zipFile);
        } catch (IOException e) {
            throw new ServiceException("E01:上传压缩包失败"+e.getMessage());
        }
        return AjaxResult.success(sb.toString());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateItemStorage(UpdateItemStorageRequestVo request) {
        if(Objects.isNull(request)){
            //throw new ServiceException("E01:提交的数据为空");
            return false;
        }
        if(Objects.isNull(request.getItemId())){
            throw new ServiceException("E01:检验项id为空");
        }
        if(Objects.isNull(request.getStorage())){
            throw new ServiceException("E01:附件数据为空");
        }
        Storage storage = request.getStorage();
        storage.setClassId(request.getItemId());
        storage.setClassify(2);
        storage.setClassTable(InspectionItem.class.getSimpleName());

        //更新附件
        StorageQuery query = new StorageQuery();
        query.setClassTable(storage.getClassTable());
        query.setClassId(storage.getClassId());
        query.setClassify(storage.getClassify());
        Storage old = storageService.getOne(WhereEntityTool.invoke(query));
        if(old!=null){
            storage.setStorageId(old.getStorageId());
        }
        storageService.saveOrUpdate(storage);
        return true;
    }

    @Override
    public List<InspectionBomVo> selectUnbindBomVo(Integer defaultCnt) {
        return baseMapper.selectUnbindBomVo(defaultCnt);
    }

    @Override
    public List<InspectionSchemeVo> getDefaultScheme() {
        SysConfig sysConfig = sysConfigService.selectConfigByKeyVal("default_inspection_scheme");
        if(sysConfig ==null){
            return Collections.emptyList();
        }
        String remark = sysConfig.getRemark();
        if(StrUtil.isBlank(remark)) {
            return Collections.emptyList();
        }
        List<String> codes = StrUtil.split(remark, ",");
        List<InspectionScheme> list = this.lambdaQuery().in(InspectionScheme::getSchemeCode, codes).list();
        List<InspectionSchemeVo> vos = new ArrayList<>();
        list.forEach(i->{
            InspectionSchemeVo info = getInfo(i.getId());
            vos.add(info);
        });
        return vos;
    }

    @Override
    public boolean refreshInspection() {
        List<InspectionSchemeVo> defaultScheme = this.getDefaultScheme();
        if(CollUtil.isEmpty(defaultScheme)){
            throw new ServiceException("E01:未找到默认方法,无法生成");
        }
        List<InspectionBomVo> inspectionBomVos = this.selectUnbindBomVo(defaultScheme.size());
        if(CollUtil.isNotEmpty(inspectionBomVos)){
            //创建对应bom的检验方案
            List<InspectionSchemeDetails> detailsList = new ArrayList<>();
            inspectionBomVos.forEach(bomVo->{
                for (InspectionSchemeVo vo : defaultScheme) {
                    long count = this.count(new LambdaQueryWrapper<InspectionScheme>().eq(InspectionScheme::getSchemeName,
                            vo.getSchemeName()).eq(InspectionScheme::getBomId, bomVo.getBomId()).eq(InspectionScheme::getIsDefault,true));
                    if(count == 0L){
                        List<InspectionItemVo> detailsVoList = vo.getDetailsVoList();
                        InspectionScheme scheme = new InspectionScheme();
                        BeanUtil.copyProperties(vo,scheme);
                        scheme.setId(IdUtils.singletonSnowId());
                        scheme.setBomId(bomVo.getBomId());
                        scheme.setItemId(bomVo.getItemId());
                        scheme.setItemName(bomVo.getItemName());
                        scheme.setItemCode(bomVo.getItemCode());
                        scheme.setSchemeCode("JYFA-" + String.format("%06d", inspectionSchemeMapper.countWithDel()+1));
                        scheme.setIsDefault(true);
                        //明细，绑定关系
                        this.save(scheme);
                        detailsVoList.forEach(detail->{
                            InspectionSchemeDetails details = new InspectionSchemeDetails();
                            details.setInspectionId(scheme.getId());
                            details.setItemId(detail.getId());
                            detailsList.add(details);
                        });
                    }
                }
            });
            if(CollUtil.isNotEmpty(detailsList)){
                inspectionSchemeDetailsService.saveBatch(detailsList);
            }
        }
        return true;
    }

    @Override
    public AjaxResult doImportCheck(MultipartFile file) throws Exception {
        return null;
    }

    @Data
    static class ImportCheckData{
        List<InspectionBomVo> inspectionBomVos = new ArrayList<>();
        List<InspectionExcelVo> list = new ArrayList<>();// excel数组
        Map<String, Long> checkTypeMap = new HashMap<>();

    }



    private boolean isImage(String suffix){
        if(StrUtil.isBlank(suffix)){
            return false;
        }
        return Arrays.asList(MimeTypeUtils.IMAGE_EXTENSION).contains(suffix.toLowerCase());
    }

    private Storage createItemZipStorage(String name, String dirName, File file,Long classId) {
        String type = com.qijian.common.utils.file.FileUtils.getFileType(name.substring(name.lastIndexOf(".") + 1));
        Storage storage = new Storage();
        storage.setClassId(classId); //item_id
        storage.setClassTable(InspectionItem.class.getSimpleName());
        storage.setClassify(2);
        storage.setName(com.qijian.common.utils.file.FileUtils.getFileNameNoEx(name));
        storage.setStorageType(Storage.StorageType.ALIOSS);
        storage.setRealName(name);
        storage.setSuffix(name.substring(name.lastIndexOf(".") + 1));
        storage.setType(type);
        storage.setSize(com.qijian.common.utils.file.FileUtils.getSize(file.length()));
        String filePath = AliyunOSSUtil.uploadObject2OSS(AliyunOSSUtil.getOSSClient(), file,
                "InspectionItem/uploadZip/", System.currentTimeMillis() + "." + storage.getSuffix());
        storage.setUrl(filePath);
        //一个item只有一个文件，如果有重复的，用最新的文件替换掉
        StorageQuery query = new StorageQuery();
        query.setClassTable(storage.getClassTable());
        query.setClassId(storage.getClassId());
        query.setClassify(storage.getClassify());
        Storage old = storageService.getOne(WhereEntityTool.invoke(query));
        if(old!=null){
            storage.setStorageId(old.getStorageId());
        }
        return storage;
    }

    /***
     * 获取类型拼接字符串
     * @return
     */
    private List<String> getInspectionTypeList(){
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType("inspection_type");
        List<SysDictData> inspectionTypeList = sysDictDataService.selectDictDataList(sysDictData);
        List<String> inspectionType = new ArrayList<>();
        if(CollUtil.isNotEmpty(inspectionTypeList)){
            inspectionTypeList.forEach(type->{
                SysDictData d = new SysDictData();
                d.setDictType(type.getRemark());
                List<SysDictData> subDicts = sysDictDataService.selectDictDataList(d);
                if(CollUtil.isNotEmpty(subDicts)){
                    subDicts.forEach(subType->{
                        //拼接最终的类型
                        String resType = type.getDictValue()+" / "+subType.getDictValue();
                        inspectionType.add(resType);
                    });
                }
            });
        }
        return inspectionType;
    }

    @Override
    public Page<InspectionSchemeVo> pageForOutInspection(Page<InspectionScheme> page, QueryWrapper<InspectionSchemeQuery> queryWrapper) {
        return this.baseMapper.pageForOutInspection(page,queryWrapper);
    }
}
